package com.milling.web.controller.business;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.milling.business.GlobalVariable;
import com.milling.business.domain.WmsBoxHole;
import com.milling.business.domain.WmsBoxInfo;
import com.milling.business.domain.WmsNeedleSortting;
import com.milling.business.service.IWmsBoxHoleService;
import com.milling.business.service.IWmsBoxInfoService;
import com.milling.business.service.IWmsNeedleSorttingService;
import com.milling.common.annotation.Log;
import com.milling.common.core.controller.BaseController;
import com.milling.common.core.domain.AjaxResult;
import com.milling.common.core.page.TableDataInfo;
import com.milling.common.core.redis.RedisCache;
import com.milling.common.enums.BusinessType;
import com.milling.common.utils.SocketUtils;
import com.milling.common.utils.StringUtils;
import com.milling.common.utils.modbus.ModbusServiceFactory;
import com.milling.common.utils.modbus.ModbusTcpService;
import com.milling.common.utils.poi.ExcelUtil;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 分拣托盘Controller
 *
 *         启动 M1写入1-分拣启动     M1写入0-分拣结束
 *         运行模式 M0写入0手动 M0写入1自动
 *         暂停 M2写入0暂停
 *         M2写入1继续
 *         初始化 M3写入1，延时50毫秒，M3写入0
 *         空跑模式 M19写入0关 M19写入1开
 *         故障解除 M4写入1，延时50毫秒，M4写入0
 *         蜂鸣器 M1504 写入1开蜂鸣器 写入0关蜂鸣器
 *
 * @author X
 * @date 2025-05-23
 */
@Configuration
@RestController
@RequestMapping("/business/sorting")
public class WmsNeedleSorttingController extends BaseController
{
    @Autowired
    private IWmsNeedleSorttingService wmsNeedleSorttingService;

    // 从参数中读取IP、端口、slaveId和连接池大小
    @Value("${modbus.sorting.host:192.168.237.178}")
    private String host; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.port:502}")
    private int port; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.poolSize:5}")
    private int poolSize; // 从配置文件或命令行参数中读取

    @Value("${modbus.sorting.slaveId:1}")
    private int slaveId;

    @Value("${sorting.scanner.instockip}")
    private String instockIp;

    @Value("${sorting.scanner.port}")
    private int instockPort;

    // 获取Modbus服务实例
    private ModbusTcpService modbusTcpService;
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IWmsBoxInfoService wmsBoxInfoService;

    @Autowired
    private IWmsBoxHoleService wmsBoxHoleService;

    @PostConstruct
    public void init() {
        // 初始化 Modbus 服务
        modbusTcpService = ModbusServiceFactory.getModbusService(host, port, poolSize);
        logger.info("FetchTasks Modbus服务初始化完成 - {}:{}", host, port);

        // 初始化扫码器连接
//        initConnection();
    }
    /**
     * 查询分拣托盘列表
     */
    @PreAuthorize("@ss.hasPermi('business:sortting:list')")
    @GetMapping("/list")
    public TableDataInfo list(WmsNeedleSortting wmsNeedleSortting)
    {
        startPage();
        List<WmsNeedleSortting> list = wmsNeedleSorttingService.selectWmsNeedleSorttingList(wmsNeedleSortting);

        wmsNeedleSorttingService.sysncNeedleSortingStatus();


        try {
            boolean[] result = modbusTcpService.readCoilsMitsubishi(
                    1,    // 从站 ID
                    8192+1,  // 起始地址（例如 M100 对应地址 100）
                    1    // 读取的线圈数量
            );
            logger.info("读取结果M1: " + result);

            result = modbusTcpService.readCoilsMitsubishi(
                    1,    // 从站 ID
                    8192+50,  // 起始地址（例如 M100 对应地址 100）
                    1    // 读取的线圈数量
            );
            logger.info("读取结果M50: " + result);

            String writeResult = modbusTcpService.writeCoilMitsubishi(
                    1,      // 从站ID
                    8192+1,   // 要写入的线圈地址
                    true    // 写入值
            );
            logger.info("写入结果M1: " + writeResult);

            writeResult = modbusTcpService.writeCoilMitsubishi(
                    1,      // 从站ID
                    8192+50,   // 要写入的线圈地址
                    true    // 写入值
            );
            logger.info("写入结果M50: " + writeResult);

            result = modbusTcpService.readCoilsMitsubishi(
                    1,    // 从站 ID
                    8192+1,  // 起始地址（例如 M100 对应地址 100）
                    1    // 读取的线圈数量
            );
            logger.info("读取结果确认M1: " + result);

            result = modbusTcpService.readCoilsMitsubishi(
                    1,    // 从站 ID
                    8192+50,  // 起始地址（例如 M100 对应地址 100）
                    1    // 读取的线圈数量
            );
            logger.info("读取结果确认M50: " + result);

        } catch (ModbusTransportException e) {
            logger.error("Modbus 通信异常: " + e.getMessage());
        }

        logger.info(".........启动成功........");
//空盒上料
//        wmsNeedleSorttingService.fixSorttingNeedleBox();

        return getDataTable(list);
    }

    /**
     * 导出分拣托盘列表
     */
    @PreAuthorize("@ss.hasPermi('business:sortting:export')")
    @Log(title = "分拣托盘", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, WmsNeedleSortting wmsNeedleSortting)
    {
        List<WmsNeedleSortting> list = wmsNeedleSorttingService.selectWmsNeedleSorttingList(wmsNeedleSortting);
        ExcelUtil<WmsNeedleSortting> util = new ExcelUtil<WmsNeedleSortting>(WmsNeedleSortting.class);
        util.exportExcel(response, list, "分拣托盘数据");
    }

    /**
     * 获取分拣托盘详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:sortting:query')")
    @GetMapping(value = "/{needleId}")
    public AjaxResult getInfo(@PathVariable("needleId") Long needleId)
    {
        return success(wmsNeedleSorttingService.selectWmsNeedleSorttingByNeedleId(needleId));
    }

    /**
     * 新增分拣托盘
     */
    @PreAuthorize("@ss.hasPermi('business:sortting:add')")
    @Log(title = "分拣托盘", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody WmsNeedleSortting wmsNeedleSortting)
    {
        return toAjax(wmsNeedleSorttingService.insertWmsNeedleSortting(wmsNeedleSortting));
    }

    /**
     * 修改分拣托盘
     */
    @PreAuthorize("@ss.hasPermi('business:sortting:edit')")
    @Log(title = "分拣托盘", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody WmsNeedleSortting wmsNeedleSortting)
    {
        return toAjax(wmsNeedleSorttingService.updateWmsNeedleSortting(wmsNeedleSortting));
    }

    /**
     * 删除分拣托盘
     */
    @PreAuthorize("@ss.hasPermi('business:sortting:remove')")
    @Log(title = "分拣托盘", businessType = BusinessType.DELETE)
    @DeleteMapping("/{needleIds}")
    public AjaxResult remove(@PathVariable Long[] needleIds)
    {
        return toAjax(wmsNeedleSorttingService.deleteWmsNeedleSorttingByNeedleIds(needleIds));
    }


    @Log(title = "初始化", businessType = BusinessType.OTHER)
    @PostMapping("/initSort")
    public AjaxResult initSort(@RequestBody WmsNeedleSortting wmsNeedleSortting)
    {
        logger.info("初始化分拣开始");
        writeCoilMitsubishi(8192+3,  true);
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        writeCoilMitsubishi(8192+3,  false);

//        GlobalVariable.initSortingParam();
        wmsNeedleSorttingService.initSortingParam();

        logger.info("初始化分拣完成");
        return AjaxResult.success();
    }

    /**
     * 故障解除 M4写入1，延时50毫秒，M4写入0
     * @return
     */
    @Log(title = "故障解除", businessType = BusinessType.OTHER)
    @PostMapping("/clearFault")
    public AjaxResult clearFault()
    {
        logger.info("开始处理 故障解除 ");
        writeCoilMitsubishi(8192+4,  true);
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        writeCoilMitsubishi(8192+4,  false);

        logger.info("处理完成 故障解除");
        return AjaxResult.success();
    }

    /**
     * 启动/结束  M1写入0启动,  M1写入1结束
     * @return
     */
    @Log(title = "启动/结束", businessType = BusinessType.OTHER)
    @PostMapping("/start")
    public AjaxResult start(@RequestBody String jsonString)
    {
        logger.info("启动/结束 操作开始 " + jsonString);
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        int operate = jsonObject.getIntValue("operate");

        if( operate == 0) {
            writeCoilMitsubishi(8192+1,  false);
        } else if (operate == 1) {
            writeCoilMitsubishi(8192+1,  true);

            writeCoilMitsubishi(8192+50,  true);
        }

        logger.info("启动/结束 操作结束");
        return AjaxResult.success();
    }

    /**
     * 暂停/继续  M2写入0暂停,  M2写入1继续
     * @return
     */
    @Log(title = "暂停/继续", businessType = BusinessType.OTHER)
    @PostMapping("/suspend")
    public AjaxResult suspend(@RequestBody String jsonString)
    {
        logger.info("暂停/继续 操作开始 " + jsonString);
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        int operate = jsonObject.getIntValue("operate");

        writeCoilMitsubishi(8192+2, operate == 1 ? true : false);

        logger.info("暂停/继续 操作结束");
        return AjaxResult.success();
    }

    /**  蜂鸣器 M1504 写入1开蜂鸣器 写入0关蜂鸣器
     *
     * @param jsonString
     * @return
     */
    @Log(title = "蜂鸣器", businessType = BusinessType.OTHER)
    @PostMapping( "/buzzer")
    public AjaxResult buzzer(@RequestBody String jsonString)
    {
        logger.info("蜂鸣器操作开始 " + jsonString);
        JSONObject jsonObject = JSONObject.parseObject(jsonString);
        int operate = jsonObject.getIntValue("operate");

        writeCoilMitsubishi(8192+1504, operate == 1 ? true : false);
        logger.info("蜂鸣器操作结束");
        return AjaxResult.success();
    }

    @Log(title = "分拣状态检查", businessType = BusinessType.OTHER)
    @PostMapping( "/checkSortingStatus")
    public AjaxResult checkSortingStatus() {
        AjaxResult ajaxResult = new AjaxResult();
        try {
            boolean[] result = modbusTcpService.readCoilsMitsubishi(
                    1,
                    8192+1,
                    4
            );
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("start", result[0]);
            jsonObject.put("suspend", result[1]);
            jsonObject.put("initSort", result[2]);
            jsonObject.put("clearFault", result[3]);
            result = modbusTcpService.readCoilsMitsubishi(
                    1,
                    8192+1504,
                    1
            );
            ajaxResult.put("buzzer", result[0]);
        } catch (ModbusTransportException e) {
//            throw new RuntimeException(e);
            logger.error("获取分拣机分拣状态失败: " + e.getMessage());
            return new AjaxResult().put("code", 500).put("message", "获取分拣机分拣状态失败");
        }
        return ajaxResult;
    }


    private void writeCoilMitsubishi(int coilAddress, boolean value) {
        try {
            String writeResult = modbusTcpService.writeCoilMitsubishi(1, coilAddress, value);
            logger.info("写入结果: " + writeResult);

            boolean[] result = modbusTcpService.readCoilsMitsubishi(1,coilAddress, 1);
            logger.info("读取结果 M"+ (coilAddress - 8192) + "： " + result);
        } catch (ModbusTransportException e) {
            logger.error("Modbus 通信异常: " + e.getMessage());
        } catch (Exception e) {
            logger.error("Modbus 通信异常: " + e.getMessage());
        }
    }

    @Log(title = "分拣扫码", businessType = BusinessType.OTHER)
    @PostMapping( "/scanQrcode")
    public AjaxResult scanQrcode() {
        logger.error("扫码任务，正在扫码");

        redisCache.deleteObject("QRCODE-VALUE");

        // 异步执行扫码任务
        CompletableFuture.runAsync(() -> {
            try (SocketUtils socketUtils = new SocketUtils(instockIp, instockPort)) {
                socketUtils.sendMessage("start");
            } catch (Exception e) {
                logger.error("扫码异常 boxId: {} ", e.getMessage());
            }
        });

        String qrcode = "NoRead";
        int maxAttempts = 20; // 最大尝试次数，防止无限循环
        int attemptCount = 0;

        while (qrcode.length() != 12 && attemptCount < maxAttempts) {
            try {
                Thread.sleep(500);
                String cachedQrcode = redisCache.getCacheObject("QRCODE-VALUE");

                if (cachedQrcode != null) {
                    qrcode = cachedQrcode;
                    logger.info("扫码结果: {}", qrcode);
                }

                attemptCount++;
            } catch (InterruptedException e) {
                logger.warn("扫码任务被中断");
                Thread.currentThread().interrupt(); // 恢复中断状态
                break;
            } catch (Exception e) {
                logger.error("获取二维码缓存时发生异常", e);
                break;
            }
        }

        if (qrcode.length() != 12) {
            logger.warn("未获取到有效二维码，最终结果: {}", qrcode);
        }

        String[] plcData = new String[50];
        for (int i = 0; i < plcData.length; i++) {
            plcData[i] = "";
        }
        Integer drillcount = 0;
        WmsBoxInfo wmsBoxInfo = new WmsBoxInfo();
        wmsBoxInfo.setBoxCode(qrcode);
        List<WmsBoxInfo> list = wmsBoxInfoService.selectWmsBoxInfoList(wmsBoxInfo);
        if (list.size() > 0) {
            WmsBoxInfo boxInfo = list.get(0);
            WmsBoxHole hole = new WmsBoxHole();
            hole.setBoxId(boxInfo.getId());
            List<WmsBoxHole> holeList = wmsBoxHoleService.selectWmsBoxHoleList(hole);
            if (holeList.size() > 0) {
                for (int i = 0; i < holeList.size(); i++) {
                    WmsBoxHole hole1 = holeList.get(i);
                    String drillinfo = hole1.getDrillInfo();
                    if(StringUtils.isNotEmpty(drillinfo)) {
                        plcData[i] = drillinfo;
                        drillcount++;
                    }
                }
            }
        }

        String jsonPlcData = JSON.toJSONString(plcData);

        logger.info("sortingData 分拣数据: " + jsonPlcData);

        // 构造一个统一的消息格式
        Map<String, Object> message = new HashMap<>();
        message.put("type", "data"); // 数据类型
        message.put("content", jsonPlcData);
        message.put("qrcode", qrcode); // 二维码
        message.put("drillcount", drillcount);

        AjaxResult ajaxResult = new AjaxResult();
        ajaxResult.put("data", message);

        return ajaxResult;

    }
}
